package executor

import (
	"bytes"
	"context"
	"encoding/json"
	"github.com/parnurzeal/gorequest"
	"goproject/builder"
	"goproject/commonType"
	"goproject/logger"
	"goproject/mongodb/record"
	"goproject/mongodb/task"
	"goproject/mongodb/testCase"
	"goproject/mongodb/testMicroservice"
	responseproxy "goproject/responseProxy"
	"io/ioutil"
	"net/http"
)

func HandleTestMicroservices(c *context.Context, testMicroservice commonType.TestMicroservice, testMicroserviceStore *testMicroservice.Store, taskStore *task.Store, testCaseStore *testCase.Store, recordStore *record.Store) {
	log := logger.GetLogger()
	ctx := context.Background() // 创建独立的 context
	testMicroserviceDone := make(chan bool)
	record, err := recordStore.Get(ctx, *testMicroservice.RecordID)
	if err != nil {
		log.Error("获取记录失败: ", err)
		return
	}
	if record.TaskID == nil {
		log.Errorf("record.TaskID 为空: %v", record)
		return
	}
	task, err := taskStore.Get(ctx, *record.TaskID)
	if err != nil {
		log.Error("获取任务失败: ", err)
		return
	}
	downstreamServices, err := builder.GetDownstreamMicroservices(&ctx, task, testMicroservice, testMicroserviceStore)
	if err != nil {
		log.Error("获取下游微服务失败: ", err)
		return
	}
	log.Infof("下游服务: %v", downstreamServices)
	for {
		// 判断是否具有下游服务
		if canExecute(c, testMicroservice, testMicroserviceStore, downstreamServices) {
			log.Infof("开始执行测试微服务: %s", testMicroservice.Name)
			testMicroservice.TestStatus = 1
			err := testMicroserviceStore.Update(ctx, testMicroservice)
			if err != nil {
				log.Errorf("更新测试微服务状态为执行中失败: %s", err)
				return
			}
			executeTest(&ctx, testMicroservice, testMicroserviceDone, testCaseStore, testMicroserviceStore, downstreamServices, taskStore, recordStore)
			testMicroservice.TestStatus = 2
			err = testMicroserviceStore.Update(ctx, testMicroservice)
			if err != nil {
				log.Errorf("更新测试微服务状态为执行完成失败: %s", err)
				return
			}
			log.Infof("测试微服务 %s 执行完成", testMicroservice.Name)
			break
		}
	}
}

// 判断是否可以执行
func canExecute(c *context.Context, testMicroservice commonType.TestMicroservice, testMicroserviceStore *testMicroservice.Store, downstreamMicroservices []commonType.TestMicroservice) bool {
	log := logger.GetLogger()
	ctx := context.Background()
	if len(downstreamMicroservices) > 0 {
		for _, service := range downstreamMicroservices {
			tm, err := testMicroserviceStore.GetByNameAndRecordId(ctx, service.Name, *testMicroservice.RecordID)
			if err != nil {
				log.Errorf("获取下游微服务状态失败: %s", err)
				return false
			}
			if tm.TestStatus != 2 {
				log.Infof("下游微服务 %s 的测试状态未完成，无法执行当前微服务 %s", service.Name, testMicroservice.Name)
				return false
			}
		}
	}
	log.Infof("所有下游微服务的测试状态均已完成，可以执行当前微服务 %s", testMicroservice.Name)
	return true
}

// 执行测试
func executeTest(c *context.Context, testMicroservice commonType.TestMicroservice, testMicroserviceDone chan bool, testCaseStore *testCase.Store, testMicroserviceStore *testMicroservice.Store, downstreamMicroservices []commonType.TestMicroservice, taskStore *task.Store, recordStore *record.Store) {
	log := logger.GetLogger()
	testcaseDone := make(chan bool)
	testCaseList, err := builder.GenerateTestCases(c, testCaseStore, testMicroservice, downstreamMicroservices)
	if err != nil {
		log.Errorf("生成测试用例失败: %s", err)
		return
	}
	log.Infof("生成测试用例成功，共 %d 条", len(testCaseList))
	podname, namespace := getPodNameAndNamespace(c, testMicroservice, taskStore, recordStore)
	for _, testCase := range testCaseList {
		ctx := context.Background()
		go executeTestCase(&ctx, testCase, testCaseStore, testcaseDone, podname, namespace, testMicroservice)
	}
	for i := 0; i < len(testCaseList); i++ {
		<-testcaseDone
	}
	testMicroservice.TestStatus = 2
	ctx := context.Background()
	err = testMicroserviceStore.Update(ctx, testMicroservice)
	if err != nil {
		log.Errorf("更新测试微服务状态为执行完成失败: %s", err)
		return
	}
	log.Infof("所有测试用例执行完成，测试微服务 %s 状态更新为执行完成", testMicroservice.Name)
	testMicroserviceDone <- true
}

// 执行测试用例
func executeTestCase(c *context.Context, testCase commonType.TestCase, testCaseStore *testCase.Store, testcaseDone chan bool, podname string, namespace string, testMicroservice commonType.TestMicroservice) {
	log := logger.GetLogger()
	ctx := context.Background()
	testCase.Status = 1
	if testCase.ID == nil || testCase.ID.IsZero() {
		log.Errorf("测试用例ID为空 %s", testCase.Response)
		return
	}
	_, err := testCaseStore.Update(ctx, testCase)
	if err != nil {
		log.Errorf("更新测试用例状态为执行中失败: %s", err)
		return
	}
	log.Infof("开始执行测试用例: %s", testCase.ID.Hex())
	filternames := []string{}
	for _, dp := range testCase.Dependency {
		filtername, err := responseproxy.ApplyEnvoyFilter(namespace, testMicroservice.Name, dp.Response)
		if err != nil {
			log.Errorf("应用 EnvoyFilter 失败: %s", err)
			return
		}
		filternames = append(filternames, filtername)
		log.Infof("应用 EnvoyFilter 成功: %s", filtername)
	}
	newTestCase, _ := sendRequest(&ctx, testCase, testCaseStore, testMicroservice, namespace)
	newTestCase.Status = 2
	_, err = testCaseStore.Update(ctx, newTestCase)
	if err != nil {
		log.Errorf("更新测试用例状态为执行完成失败: %s", err)
		return
	}
	for _, fn := range filternames {
		responseproxy.DeleteEnvoyFilter(namespace, fn)
		log.Infof("删除 EnvoyFilter 成功: %s", fn)
	}
	testcaseDone <- true
	log.Infof("测试用例执行完成: %s", testCase.ID.Hex())
}

// 通过testMicroservice.ID获取podName与namespace
func getPodNameAndNamespace(c *context.Context, testMicroservice commonType.TestMicroservice, taskStore *task.Store, recordStore *record.Store) (string, string) {
	log := logger.GetLogger()
	ctx := context.Background()
	record, err := recordStore.Get(ctx, *testMicroservice.RecordID)
	if err != nil {
		log.Errorf("获取记录失败: %s", err)
		return "", ""
	}
	task, err := taskStore.Get(ctx, *record.TaskID)
	if err != nil {
		log.Errorf("获取任务失败: %s", err)
		return "", ""
	}
	namespace := task.SelectedReq.Namespace
	podName := ""
	for _, node := range task.TraceTree.Nodes {
		if node.ServiceName == testMicroservice.Name {
			podName = node.PodName
			break
		}
	}
	log.Infof("获取 PodName 和 Namespace 成功: %s, %s", podName, namespace)
	return podName, namespace
}

func sendRequest(c *context.Context, testCase commonType.TestCase, testCaseStore *testCase.Store, testMicroservice commonType.TestMicroservice, namespace string) (commonType.TestCase, error) {

	log := logger.GetLogger()
	ctx := context.Background() // 创建独立的 context

	log.Infof("开始发送请求: %s", testCase.SelectedReq.URL)
	// 构造请求数据
	var requestData = commonType.RequestData{
		Namespace:   namespace,
		ServiceName: testMicroservice.Name,
		RequestDefine: commonType.RequestDefine{
			URL:    testCase.SelectedReq.URL,
			Method: testCase.SelectedReq.Method,
			Header: testCase.SelectedReq.Header,
			Data:   testCase.SelectedReq.Data,
		},
	}
	jsonData, err := json.Marshal(requestData)
	if err != nil {
		log.Errorf("序列化请求数据失败: %s", err)
		return commonType.TestCase{}, err
	}

	// 创建Gorequest的HTTP客户端
	gorequestClient := gorequest.New()
	// 设置请求头和请求方法
	resp, body, errs := gorequestClient.CustomMethod("POST", "http://127.0.0.1:30816/bridge/process").
		Set("Content-Type", "application/json").
		Send(string(jsonData)).
		End()

	// 检查请求是否testCase.ID有错误发生
	if errs != nil {
		log.Errorf("发送请求时发生错误: %v", errs)
		return commonType.TestCase{}, err
	}

	// 确保响应体关闭
	defer resp.Body.Close()

	// 更新测试用例的响应信息
	rsp := http.Response{
		StatusCode: resp.StatusCode,
		Body:       ioutil.NopCloser(bytes.NewBufferString(body)),
	}

	testCase.Response, _ = convertResponse(&rsp)

	// 更新测试用例
	testCase, errUpdate := testCaseStore.Update(ctx, testCase)
	if errUpdate != nil {
		log.Errorf("更新测试用例失败: %s", errUpdate)
		return commonType.TestCase{}, err
	}
	log.Infof("请求响应接收成功: %s", testCase.Response.Body)
	return testCase, nil
}

// convertResponse 将 HTTP 响应转换为 commonType.StoredResponse 类型
func convertResponse(r *http.Response) (commonType.StoredResponse, error) {
	log := logger.GetLogger()
	bodyBytes, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Errorf("读取响应体失败: %s", err)
		return commonType.StoredResponse{}, err
	}
	// 确保关闭原始响应体
	r.Body.Close()

	// 将响应体转换为 map[string]interface{}
	var bodyMap map[string]interface{}
	err = json.Unmarshal(bodyBytes, &bodyMap)
	if err != nil {
		log.Errorf("解析响应体失败: %s", err)
		return commonType.StoredResponse{}, err
	}

	log.Infof("响应转换成功，状态码: %d", r.StatusCode)
	return commonType.StoredResponse{
		StatusCode: r.StatusCode,
		Body:       bodyMap,
	}, nil
}
